﻿#region copyright
//<copyright>
// Copyright(C) 2012 TrackerRealm Corporation
// This file is part of the open source project - Jazz. http://jazz.codeplex.com
// 
// Jazz is open software: you can redistribute it and/or modify it 
// under the terms of the GNU Affero General Public License (AGPL) as published by 
// the Free Software Foundation, version 3 of the License.
// 
// Jazz is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty 
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
//  See the GNU Affero General Public License (AGPL) for more details.
// 
// You should have received a copy of the GNU General Public 
// License along with Jazz.  If not, see <http://www.gnu.org/licenses/>.
//
// REMOVAL OF THIS NOTICE IS VIOLATION OF THE COPYRIGHT. 
//</copyright>
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using TrackerRealm.Jazz.Common;
using C = TrackerRealm.Jazz.Common.JazzConstants;

namespace TrackerRealm.Jazz.Client
{
    /// <summary>
    /// jMemberInfo is a Jazz wrapper class for .net 'MemberInfo'.
    /// </summary>
    public abstract class jMemberInfo
    {
        #region Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="member"></param>
        /// <param name="jazzObj"></param>
        internal jMemberInfo(MemberInfo member, jObject jazzObj)
        {
            if (member != null)
                this.Name = member.Name;
            else
                this.Name = "";
            this.member = member;
            this.jazzObject = jazzObj;
            if (member != null)
            {
                object[] uiAttArray =  member.GetCustomAttributes(typeof(UIAttribute), true);
                if (uiAttArray.Length >= 1)
                {
                    isUI = true;
                    UIAttribute uiAttr = (UIAttribute)uiAttArray[0];
                    this.Tag = jClass.GetTag(member, uiAttr.TagName, "");
                }
            }
        }
        #endregion
        #region JazzObject
        /// <summary>
        /// 
        /// </summary>
        protected jObject jazzObject;
        #endregion

        #region Member
        /// <summary>
        /// 
        /// </summary>
        protected MemberInfo member;
        /// <summary>
        /// Returns the wrapped 'MemberInfo' instance.
        /// </summary>
        public MemberInfo Member
        {
            get { return this.member; }
        }
        #endregion
        #region Tag
        /// <summary>
        /// Returns a Tag object otherwise a blank string.
        /// </summary>
        public object Tag { get; private set; }
        #endregion
        #region Name
        /// <summary>
        /// 
        /// </summary>
        public string Name
        {
            get;
            protected set;
        }
        #endregion
        #region IsUI
        /// <summary>
        /// 
        /// </summary>
        protected bool isUI = false;
        /// <summary>
        /// Returns true if this member has UI attribute.
        /// </summary>
        public bool IsUI
        {
            get { return this.isUI; }
        }
        #endregion
        #region IsEmpty
        /// <summary>
        /// Returns true if this is an empty member.
        /// </summary>
        public virtual bool IsEmpty
        {
            get { return false; }
        }
        #endregion
        #region IsMethod
        /// <summary>
        /// Returns true if this member is a method.
        /// <para>Note: True will be returned if this member is a property setter or getter.</para>
        /// </summary>
        public virtual bool IsMethod
        {
            get { return true; }
        }
        #endregion
        #region IsProperty
        /// <summary>
        /// Returns true if this member is a property.
        /// <para>Note: Property setter and getters are methods.</para>
        /// </summary>
        public virtual bool IsProperty
        {
            get { return false; }
        }
        #endregion
        #region IsWriteAccessor
        /// <summary>
        /// Returns true if this member is a property write accessor (setter).
        /// <para>Note: Property read and write accessors are methods.</para>
        /// </summary>
        public virtual bool IsWriteAccessor
        {
            get { return false; }
        }
        #endregion
        #region IsReadAccessor
        /// <summary>
        /// Returns true if this member is a property read accessor (getter).
        /// <para>Note: Property read and write accessors are methods.</para>
        /// </summary>
        public virtual bool IsReadAccessor
        {
            get { return false; }
        }
        #endregion
        #region Property WriteAccessor
        /// <summary>
        /// Returns the property write accessor (setter) if this instance is a property,
        /// otherwise an empty accessor is returned.
        /// </summary>
        public virtual jWriteAccessor WriteAccessor
        {
            get { return jWriteAccessor.Empty; }
            protected internal set { throw new InvalidOperationException(); }
        }
        #endregion
        #region Property ReadAccessor
        /// <summary>
        /// Returns the property write accessor (setter) if this instance is a property,
        /// otherwise an empty accessor is returned.
        /// </summary>
        public virtual jReadAccessor ReadAccessor
        {
            get { return jReadAccessor.Empty; }
            protected internal set { throw new InvalidOperationException(); }
        }
        #endregion
        #region IsGrey
        /// <summary>
        /// Returns true if this member is not accessible due to a "Grant" attribute and this member is otherwise accessible (declared public).
        /// </summary>
        public virtual bool IsGrey
        {
            get { return false; }
        }
        #endregion
        //
        // Method specific properties and methods
        //
        #region MethodInfo
        /// <summary>
        /// If this member is a method ('IsMethod') then the MethodInfo object is returned.
        /// </summary>
        public virtual MethodInfo MethodInfo
        {
            get { throw new InvalidOperationException("This member is not a 'jMethodInfo'."); }
        }
        #endregion
        #region Execute ()
        /// <summary>
        /// Executes the method provided this member is a method (see <see cref="IsMethod"/>).
        /// </summary>
        /// <returns></returns>
        public virtual object Execute()
        {
            throw new InvalidOperationException("This member is not a method.");
        }
        #endregion
        #region Execute (jObject flow)
        /// <summary>
        /// Executes the method provided this member is a method (see <see cref="IsMethod"/>).
        /// </summary>
        /// <param name="flow"></param>
        /// <returns></returns>
        public virtual object Execute(jObject flow)
        {
            throw new InvalidOperationException("This member is not a method.");
        }
        #endregion
        #region Execute (jObject flow, params object[] args)
        /// <summary>
        /// Executes the method provided this member is a method (see <see cref="IsMethod"/>).
        /// </summary>
        /// <param name="jazzObject"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public virtual object Execute(jObject jazzObject, params object[] args)
        {
            throw new InvalidOperationException("This member is not a method.");
        }
        #endregion
        #region Execute (params object[] args)
        /// <summary>
        /// Executes the method provided this member is a method (see <see cref="IsMethod"/>).
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        public virtual object Execute(params object[] args)
        {
            throw new InvalidOperationException("This member is not a method.");
        }
        #endregion
        #region IsPublic
        /// <summary>
        /// Returns true if this a method and it is executable.
        /// </summary>
        public virtual bool IsPublic
        {
            get { return false; }
        }
        #endregion
        #region IsExecutable
        /// <summary>
        /// Returns true if this a method and it is executable.
        /// <para>This is a convenience method providing the same functionality
        /// as '<see cref="IsPublic"/>'.</para>
        /// </summary>
        public virtual bool IsExecutable
        {
            get { return this.IsPublic; }
        }
        #endregion
        //
        // Property Info specific properties and methods
        //
        #region PropertyInfo
        /// <summary>
        /// 
        /// </summary>
        public virtual PropertyInfo PropertyInfo
        {
            get { throw new InvalidOperationException("This member is not a 'jPropertyInfo'.");}
        }
        #endregion
        #region CanRead
        /// <summary>
        /// Returns true if 'IsProperty' is true and the 'Read' accessor is usable.
        /// </summary>
        public virtual bool CanRead
        {
            get { return false; }
        }
        #endregion
        #region CanWrite
        /// <summary>
        /// Returns true if 'IsProperty' is true and the 'Write' accessor is usable.
        /// </summary>
        public virtual bool CanWrite
        {
            get { return false; }
        }
        #endregion
        #region Read
        /// <summary>
        /// If this member can be read ('<see cref="CanRead"/>'),
        /// then the Read method returns the value of the property (member),
        /// <para>otherwise a 'InvalidOperationException' is thrown.</para>
        /// </summary>
        /// <param name="jazzObj"></param>
        /// <returns></returns>
        public virtual object Read(jObject jazzObj)
        {
            throw new InvalidOperationException(string.Format("This member, '{0}':'{1}', is not a property.", this.member.Name, this.member.DeclaringType.FullName));
        }
        /// <summary>
        /// If this member can be read ('<see cref="CanRead"/>'),
        /// then the Read method returns the value of the property (member),
        /// <para>otherwise a 'InvalidOperationException' is thrown.</para>
        /// </summary>
        /// <returns></returns>
        public virtual object Read()
        {
            throw new InvalidOperationException(string.Format("This member, '{0}':'{1}', is not a property.", this.member.Name, this.member.DeclaringType.FullName));
        }
        #endregion
        #region Write
        /// <summary>
        /// If this member can be written ('<see cref="CanWrite"/>'),
        /// then the Write method sets the value of the property (member),
        /// <para>otherwise a 'InvalidOperationException' is thrown.</para>
        /// </summary>
        /// <param name="jazzObj"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public virtual object Write(jObject jazzObj, object value)
        {
            throw new InvalidOperationException("This member is not a property");
        }
        /// <summary>
        /// If this member can be written ('<see cref="CanWrite"/>'),
        /// then the Write method sets the value of the property (member),
        /// <para>otherwise a 'InvalidOperationException' is thrown.</para>
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public virtual object Write(object value)
        {
            throw new InvalidOperationException("This member is not a property");
        }
        #endregion
        #region ToString
        /// <summary>
        /// Designed to be useful for Visual Studio.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string name = "";
            if (this.Name == "")
            {
                if (this.IsEmpty) 
                    name = "<" + C.EMPTY + ">";
            }
            else
                name = this.Name;
            return this.GetType().Name + ":'" + name + "'";
        }
        #endregion
    }
}
